package com.qf.handler;

import com.qf.common.R;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.validation.BindException;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.validation.ConstraintViolationException;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;


/**
 * @Author Ayases
 * @Date 2025/6/12 10:52
 * @Desc
 */

@ControllerAdvice
public class GlobalValidationExceptionHandler {

    private static final Logger log = LoggerFactory.getLogger(GlobalValidationExceptionHandler.class);
    // 错误信息分隔符
    private static final String ERROR_DELIMITER = "；";

    /**
     * 处理表单提交验证异常
     */
    @ExceptionHandler(BindException.class)
    @ResponseBody
    public R handleBindException(BindException ex) {
        return buildValidationError(ex.getBindingResult());
    }

    /**
     * 处理JSON参数验证异常
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    @ResponseBody
    public R handleMethodArgumentNotValid(MethodArgumentNotValidException ex) {
        return buildValidationError(ex.getBindingResult());
    }

    /**
     * 处理单个参数验证异常
     */
    @ExceptionHandler(ConstraintViolationException.class)
    @ResponseBody
    public R handleConstraintViolation(ConstraintViolationException ex) {
        String combinedMessage = ex.getConstraintViolations().stream()
                .map(violation -> {
                    String path = violation.getPropertyPath().toString();
                    String field = path.contains(".")
                            ? path.substring(path.lastIndexOf('.') + 1)
                            : path;
                    return formatFieldMessage(field, violation.getMessage());
                })
                .collect(Collectors.joining(ERROR_DELIMITER));

        log.warn("参数验证异常: {}", combinedMessage);
        return R.error(400, combinedMessage);
    }

    /**
     * 统一验证错误构建方法 (支持多个错误拼接)
     */
    private R buildValidationError(BindingResult bindingResult) {
        // 1. 收集所有错误消息
        List<String> allErrorMessages = new ArrayList<>();

        // 1.1 收集字段级错误
        if (bindingResult.hasFieldErrors()) {
            bindingResult.getFieldErrors().forEach(error -> {
                String formattedMessage = formatFieldMessage(error.getField(), error.getDefaultMessage());
                allErrorMessages.add(formattedMessage);
                log.debug("字段验证失败: {} - {}", error.getField(), error.getDefaultMessage());
            });
        }

        // 1.2 收集全局错误
        if (bindingResult.hasGlobalErrors()) {
            bindingResult.getGlobalErrors().forEach(error -> {
                allErrorMessages.add(error.getDefaultMessage());
                log.debug("全局验证失败: {}", error.getDefaultMessage());
            });
        }

        // 2. 合并错误消息
        if (!allErrorMessages.isEmpty()) {
            String combinedMessage = String.join(ERROR_DELIMITER, allErrorMessages);
            log.warn("验证失败 - 共 {} 个错误: {}", allErrorMessages.size(), combinedMessage);
            return R.error(400, combinedMessage);
        }

        log.warn("未知验证异常类型: {}", bindingResult);
        return R.error(400, "请求参数不合法");
    }

    /**
     * 格式化字段错误消息（移除冗余字段名）
     */
    private String formatFieldMessage(String fieldName, String message) {
        // 移除可能的字段名前缀（如 "商品名称 不能为空" -> "不能为空"）
        String prefix = fieldName + " ";
        if (message != null && message.startsWith(prefix)) {
            return message.substring(prefix.length());
        }
        return message;
    }
}
